Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: OpenDoc Cookbook /
Chapter 2 - SamplePart Tutorial


Handling Frame Layout

Parts lay themselves out for display in a document according to the demands of their content and in negotiation with their containing parts. This process takes place through the mechanism of the part's display frames. Methods illustrating how SamplePart handles its display frames are included in this section.

SamplePart is a noncontainer part--it does not support embedding of other parts in it--so its frame layout considerations are somewhat simpler than those of container parts. Nonetheless, SamplePart participates in the layout negotiations of its containing part when it is itself embedded in another part. In addition, SamplePart supports multiple display frames, displaying itself in multiple frames and synchronizing those displays as necessary.

The DisplayFrameAdded Method

OpenDoc calls the DisplayFrameAdded method when a new display frame is created for the part, for example, after the containing part calls the draft's CreateFrame method. Generally, in response to the DisplayFrameAdded call, a part should set itself up to manage the new frame and ensure that it can handle the frame's display requirements.

The SamplePart object's implementation of the DisplayFrameAdded method performs the following actions:

  1. Sets up the presentation and view type correctly.
    The method checks the new frame's presentation and view type. If the frame's presentation is not the SamplePart main presentation type, the method sets it to be so. If the view type is null, the method sets it to frame view, the most typical preferred type.

  2. Stores part info data for the new frame.
    SamplePart creates a CFrameInfo object for this purpose and stores a reference to it in the frame's part info field.

  3. Sets the frame's window disposal flag.
    If the frame being added is a root frame, then it has a window associated with it, and the window must be disposed of when the frame is removed. The window disposal flag is checked in SamplePart's internal CleanupWindow method.

  4. Updates the part's frame list.
    Finally, the method creates a proxy for the new frame and adds a reference to the proxy to its internal display frame list.

Listing 2-9 shows the implementation of the DisplayFrameAdded method.

Listing 2-9 DisplayFrameAdded method

void SamplePart::DisplayFrameAdded( Environment*ev,
                           ODFrame*    frame )
{
   SOM_Trace("SamplePart","DisplayFrameAdded");

   if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
      frame->SetPresentation(ev, gGlobals->fMainPresentation);
   
   if ( frame->GetViewType(ev) == kODNullTypeToken )
      frame->SetViewType(ev, gGlobals->fFrameView);
      
   CFrameInfo* frameInfo = new CFrameInfo;
   frame->SetPartInfo(ev, (ODInfoType)frameInfo);
      
   if ( frame->IsRoot(ev) )
      frameInfo->SetShouldDisposeWindow(kODTrue);
   CFrameProxy* proxy = new CFrameProxy;
   proxy->InitFrameProxy(ev,frame);
   fDisplayFrames->Add(proxy);

   this->SetDirty(ev);
}

The DisplayFrameConnected Method

OpenDoc calls the DisplayFrameConnected method if the part is embedded and the containing part reads the display frame into memory, having previously written it to storage. This occurs when the frame becomes visible through scrolling or other actions. OpenDoc calls this method instead of DisplayFrameAdded because a new frame is not being created; an existing one is being reconnected to the part.

The SamplePart object's implementation of the DisplayFrameConnected method performs the following actions:

  1. Updates the part's frame list.
    The method iterates over SamplePart's list of display frames, attempting to match the frame's ID number with the ID numbers of the frame proxies in the list. If there is no match, the method adds the frame. If there is a match, the method updates the proxy's internal fields with information obtained from the frame.

  2. Ensures that the presentation is meaningful.
    The part editor must be able to display the frame, so it must recognize the presentation. In SamplePart's case, the method compares the frame's presentation to the main presentation stored in the globals structure. If it differs, the method sets it to be the main presentation.

  3. Handles the root frame case.
    If the frame is a root frame, the method does two things: it sets the window disposal flag to kODTrue, and it sets the view type to frame view.

Listing 2-10 shows the implementation of the DisplayFrameConnected method.

Listing 2-10 DisplayFrameConnected method

void SamplePart::DisplayFrameConnected( Environment*ev,
                              ODFrame*    frame )
{
    SOM_Trace("SamplePart","DisplayFrameConnected");

   ODBoolean found = kODFalse;
   CListIterator fiter(fDisplayFrames);
   for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
         fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
   {
      if ( proxy->GetID() == frame->GetID(ev) )
      {
         proxy->SetFrame(ev,frame);
         found = kODTrue;
      }
   }
   if ( found )
   {
      if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
         frame->SetPresentation(ev, gGlobals->fMainPresentation);
      
      if ( frame->IsRoot(ev) )
      {
         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
         frameInfo->SetShouldDisposeWindow(kODTrue);
         
         if ( frame->GetViewType(ev) != gGlobals->fFrameView )
            frame->SetViewType(ev, gGlobals->fFrameView);
      }
   }
   else
   {
      this->DisplayFrameAdded(ev, frame);
   }
}

The DisplayFrameRemoved Method

OpenDoc calls a part's DisplayFrameRemoved method when its containing part has permanently removed one of the part's display frames. Generally, implementations of the DisplayFrameRemoved method perform any actions required to remove the frame, including removing frames embedded within the removed frame, relinquishing foci, and updating the part's internal frame list.

The SamplePart object's implementation of the DisplayFrameRemoved method performs the following actions:

  1. Relinquishes any foci owned by the frame.
    The method calls the SamplePart object's internal RelinquishAllFoci method, which instantiates a temporary frame object to wrap the reference returned by the arbitrator for each of the foci a SamplePart frame could own: the selection focus and the menu focus. The RelinquishAllFoci method compares the focus owner with the frame to be removed, and, if they are equal, relinquishes the focus through the arbitrator and notifies the part that the focus is lost.

    The RelinquishAllFoci method uses the TempODFrame class, a C++ template class declared in the file TempObj.h, and the ODObjectsAreEqual function, defined in the file ODUtils.h. They are described in Appendix A, "OpenDoc Utilities."

  2. Cleans up the display frame references.
    The method calls the SamplePart object's internal CleanupDisplayFrame method. If this frame (that is, the frame to be removed) has a source frame, the CleanupDisplayFrame method gets a reference to the source frame and to its frame info object. It invalidates the source frame to force it to redraw without any possible effects of having been synchronized with this frame. The method notifies the source frame that it is going away and releases this frame's reference to the source frame (decrementing the source frame's reference count).

    If this frame is a root frame, then it is in a part window which is being closed, so the CleanupDisplayFrame method notifies the source frame that it no longer has a part window. Conversely, if the frame has a part window, the method closes and removes it.

    If the frame being removed has a dependent frame, the CleanupDisplayFrame method notifies it that its source frame is being removed and releases its own reference to the dependent frame.

  3. Cleans up any window associated with the frame.
    The method calls the SamplePart object's internal CleanupWindow method, which checks this frame's ShouldDisposeWindow flag. If the flag is true, the method retrieves references to the frame's OpenDoc window object and its Mac OS platform window structure. It releases the OpenDoc window object, then closes and disposes of the platform window.

  4. Cleans up the frame and removes it from the part's internal frame list.
    The method sets to null its pointer to its frame info object, then deletes the object using the ODDeleteObject utility macro (which is defined in the ODUtils.h file). Finally, the method removes this frame from its internal display frame list and sets the part's dirty flag.

If any of the preceding actions causes an exception to be thrown, the method catches it in its CATCH_ALL handler, which displays an error dialog box to the user and propagates the error.

Listing 2-11 shows the implementation of the DisplayFrameRemoved method.

Listing 2-11 DisplayFrameRemoved method

void SamplePart::DisplayFrameRemoved( Environment*ev,
                             ODFrame*  frame )
{
    SOM_Trace("SamplePart","DisplayFrameRemoved");

   TRY
      CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
      this->RelinquishAllFoci(ev, frame);
      this->CleanupDisplayFrame(ev, frame, kFrameRemoved);
      this->CleanupWindow(ev, frame);
      frame->SetPartInfo(ev, (ODInfoType) kODNULL);
      ODDeleteObject(frameInfo);
      
      CListIterator fiter(fDisplayFrames);
      for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
            fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
      {
         if ( ODObjectsAreEqual(ev, proxy->GetFrame(ev), frame) )
         {
            fiter.RemoveCurrent();
            delete proxy;
         }
      }
      this->SetDirty(ev);
   
   CATCH_ALL
      this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
      SetErrorCode(kODErrAlreadyNotified);
      RERAISE;
   ENDTRY
}

The DisplayFrameClosed Method

OpenDoc calls the DisplayFrameClosed method when a frame is closed as a result of the user closing its document. The SamplePart implementation of the DisplayFrameClosed method is virtually identical to that of its DisplayFrameRemoved method except it does not cache runtime information, so it does not set the part's dirty flag. Also, the DisplayFrameClosed method does not delete the frame proxy object because closed frames may be reconnected before the document is finally closed.

Listing 2-12 shows the implementation of the DisplayFrameClosed method.

Listing 2-12 DisplayFrameClosed method

void SamplePart::DisplayFrameClosed( Environment*ev,
                            ODFrame*   frame )
{
   SOM_Trace("SamplePart","DisplayFrameClosed");

   TRY
      CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
      this->RelinquishAllFoci(ev, frame);
      this->CleanupDisplayFrame(ev, frame, kFrameClosed);
      this->CleanupWindow(ev, frame);
      frame->SetPartInfo(ev, (ODInfoType) kODNULL);
      ODDeleteObject(frameInfo);
      
      CListIterator fiter(fDisplayFrames);
      for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
            fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
      {
         if ( proxy->GetID() == frame->GetID(ev) )
         {
            proxy->Purge(ev);
         }
      }
      
   CATCH_ALL
      this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
      SetErrorCode(kODErrAlreadyNotified);
      RERAISE;
   ENDTRY
}

The AttachSourceFrame Method

OpenDoc calls a part's AttachSourceFrame method during creation of a part window from a containing part. That is, if SamplePart is embedded in a frame of another part, and that frame is opened into a part window, the containing part iterates over its embedded frames and adds new corresponding frames in the part window. After each new embedded frame is created, the containing part calls the AttachSourceFrame method.

Listing 2-13 shows the implementation of the AttachSourceFrame method.

Listing 2-13 AttachSourceFrame method

void SamplePart::AttachSourceFrame( Environment*    ev,
                                    ODFrame*        frame,
                                    ODFrame*        sourceFrame )
{
    SOM_Trace("SamplePart","AttachSourceFrame");

   CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
   frameInfo->SetSourceFrame(ev, sourceFrame);
   frameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
   frameInfo->SetDependentFrame(ev, frame);
}

The FrameShapeChanged Method

OpenDoc calls a part's FrameShapeChanged method whenever the part's display frame's shape has been changed, either by the user or by the containing part (if this part is embedded). OpenDoc passes a pointer to the frame whose shape has changed with the method call. The basic responsibility of this method is to update all synchronized frames by propagating the new frame shape to them. To do so, the method finds all the synchronized frames, pointers to which are stored in this frame's CFrameInfo object, and calls each frame's RequestFrameShape method.

Listing 2-14 shows the implementation of the FrameShapeChanged method.

Listing 2-14 FrameShapeChanged method

void SamplePart::FrameShapeChanged( Environment*  ev,
                                    ODFrame*      frame )
{
   SOM_Trace("SamplePart","FrameShapeChanged");

   if ( !frame->IsRoot(ev) )
   {
      TempODShape frameShape = frame->AcquireFrameShape(ev, kODNULL);
      CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
      ODFrame*    displayFrame;
      
      if ( frameInfo->HasSourceFrame() )
      {
         displayFrame = frameInfo->GetSourceFrame(ev);
         
         TempODShape frameShapeCopy = frameShape->Copy(ev);
         TempODShape returnShape = displayFrame->                           RequestFrameShape(ev, frameShapeCopy, kODNULL);
         
         displayFrame->Invalidate(ev, kODNULL, kODNULL);
      }
   
      if ( frameInfo->HasDependentFrame() )
      {
         displayFrame = frameInfo->GetDependentFrame(ev);
         
         TempODShape frameShapeCopy = frameShape->Copy(ev);
         TempODShape returnShape = displayFrame->                           RequestFrameShape(ev, frameShapeCopy, kODNULL);
            
         displayFrame->Invalidate(ev, kODNULL, kODNULL);
      }
   }
}

Previous Book Contents Book Index Next

© Apple Computer, Inc.
16 JUL 1996




Navigation graphic, see text links

Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help